<!DOCTYPE html>
<html>
<head>
	<title>JSV: JSON Schema Validator</title>
	<style type="text/css">

/* 1140px CSS Fluid Grid System */

html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,address,cite,code,del,dfn,em,img,ins,q,small,strong,sub,sup,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{border:0;margin:0;padding:0}
article,aside,figure,figure img,figcaption,hgroup,footer,header,nav,section,video,object{display:block}
a img{border:0}
figure{position:relative}
figure img{width:100%}
.container{padding-left:20px;padding-right:20px}
.row{width:100%;max-width:1140px;min-width:755px;overflow:hidden;margin:0 auto}
.onecol,.twocol,.threecol,.fourcol,.fivecol,.sixcol,.sevencol,.eightcol,.ninecol,.tencol,.elevencol{margin-right:3.8%;float:left;min-height:1px}
.row .onecol{width:4.85%}
.row .twocol{width:13.45%}
.row .threecol{width:22.05%}
.row .fourcol{width:30.75%}
.row .fivecol{width:39.45%}
.row .sixcol{width:48%}
.row .sevencol{width:56.75%}
.row .eightcol{width:65.4%}
.row .ninecol{width:74.05%}
.row .tencol{width:82.7%}
.row .elevencol{width:91.35%}
.row .twelvecol{width:100%;float:left}
.last{margin-right:0}
img,object,embed{max-width:100%}
img{height:auto}
@media only screen and (max-width: 1023px) {
body{font-size:.8em;line-height:1.5em}
}
@media handheld, only screen and (max-width: 767px) {
body{font-size:16px;-webkit-text-size-adjust:none}
.row,body,.container{width:100%;min-width:0;margin-left:0;margin-right:0;padding-left:0;padding-right:0}
.row .onecol,.row .twocol,.row .threecol,.row .fourcol,.row .fivecol,.row .sixcol,.row .sevencol,.row .eightcol,.row .ninecol,.row .tencol,.row .elevencol,.row .twelvecol{width:auto;float:none;margin-left:0;margin-right:0;padding-left:20px;padding-right:20px}
}

/* Styles */

.container { padding-bottom: 20px; font-family: sans-serif; } 
.row { margin-top: 20px; }
legend { font-weight: bold; font-size: 125%; }
label {	display: block; font-weight: bold; }
.value_label { display: none; }
.value { height: 360px; font-size: 12px; tab-size: 4; }
.value, .uri { width: 100%; }
.value, .uri, .error code { font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif; }
.error { margin: 20px 0; font-size: 12px; }
.error:first-child { margin-top: 0; }
.error:last-child { margin-bottom: 0; }
.error_message { font-weight: bold; }
.error_schemaUri { margin-left: 15px; }
.error_attribute { margin-left: 15px; }
#report { padding: 20px; }
#report.valid { border: 1px solid #0f0; background-color: #efe; }
#report.invalid { border: 1px solid #f00; background-color: #fee; }

	</style>
</head>
<body class="container">
	<div class="row">
		<h1>JSV: JSON Schema Validator</h1>
		<p></p>
	</div>
	
	<form id="jsv" class="row">
		<div class="row">
			<div class="twelvecol last">
				<fieldset id="environment_properties">
					<label for="environment">Environment</label>
					<select id="environment" name="environment">
						<option value="json-schema-draft-03">JSON Schema Draft-03</option>
						<option value="json-schema-draft-02">JSON Schema Draft-02</option>
						<option value="json-schema-draft-01">JSON Schema Draft-01</option>
					</select>
				</fieldset>
			</div>
		</div>
		
		<div class="row">
			<div class="sixcol">
				<fieldset id="json_properties">
					<legend>Input</legend>
					<label id="json_label" class="value_label" for="json">Value</label>
					<textarea id="json" class="value" name="json" wrap="off"></textarea>
					<label id="json_uri_label" class="uri_label" for="json_uri">URI</label>
					<input id="json_uri" class="uri" type="text" name="json_uri" value="json">
				</fieldset>
			</div>
			
			<div class="sixcol last">
				<fieldset id="schema_properties">
					<legend>Schema</legend>
					<label id="schema_label" class="value_label" for="schema">Value</label>
					<textarea id="schema" class="value" name="schema" wrap="off"></textarea>
					<label id="schema_uri_label" class="uri_label" for="schema_uri">URI</label>
					<input id="schema_uri" class="uri" type="text" name="schema_uri" value="schema">
				</fieldset>
			</div>
		</div>
		
		<div class="row">
			<div class="twelvecol last">
				<fieldset id="controls">
					<input id="validate" type="submit" value="Validate"/>
				</fieldset>
			</div>
		</div>
	</form>
	
	<div class="row">
		<div id="report"></div>
	</div>
	
	<!-- Load Scripts -->
	
    <script type="text/javascript">

/* Code by: http://bitprophet.org/code/javascript_tab.html */ 

var TAB_CHAR = "\t";
function checkTab(evt) {
	var t = evt.target;
	var ss = t.selectionStart;
	var se = t.selectionEnd;
 
	// Tab key - insert tab expansion
	if (evt.keyCode == 9) {
		evt.preventDefault();
		
		// Special case of multi line selection
		if (ss != se && t.value.slice(ss,se).indexOf("n") != -1) {
			// In case selection was not of entire lines (e.g. selection begins in the middle of a line)
			// we ought to tab at the beginning as well as at the start of every following line.
			var pre = t.value.slice(0,ss);
			var sel = t.value.slice(ss,se).replace(/n/g,"n"+TAB_CHAR);
			var post = t.value.slice(se,t.value.length);
			t.value = pre.concat(TAB_CHAR).concat(sel).concat(post);
				   
			t.selectionStart = ss + TAB_CHAR.length;
			t.selectionEnd = se + TAB_CHAR.length;
		}
		
		// "Normal" case (no selection or selection on one line only)
		else {
			t.value = t.value.slice(0,ss).concat(TAB_CHAR).concat(t.value.slice(ss,t.value.length));
			if (ss == se) {
				t.selectionStart = t.selectionEnd = ss + TAB_CHAR.length;
			}
			else {
				t.selectionStart = ss + TAB_CHAR.length;
				t.selectionEnd = se + TAB_CHAR.length;
			}
		}
	}
	
	// Backspace key - delete preceding tab expansion, if exists
   else if (evt.keyCode==8 && t.value.slice(ss - 4,ss) == TAB_CHAR) {
		evt.preventDefault();
		
		t.value = t.value.slice(0,ss - 4).concat(t.value.slice(ss,t.value.length));
		t.selectionStart = t.selectionEnd = ss - TAB_CHAR.length;
	}
	
	// Delete key - delete following tab expansion, if exists
	else if (evt.keyCode==46 && t.value.slice(se,se + 4) == TAB_CHAR) {
		evt.preventDefault();
		
		t.value = t.value.slice(0,ss).concat(t.value.slice(ss + 4,t.value.length));
		t.selectionStart = t.selectionEnd = ss;
	}
	// Left/right arrow keys - move across the tab in one go
	else if (evt.keyCode == 37 && t.value.slice(ss - 4,ss) == TAB_CHAR) {
		evt.preventDefault();
		t.selectionStart = t.selectionEnd = ss - 4;
	}
	else if (evt.keyCode == 39 && t.value.slice(ss,ss + 4) == TAB_CHAR) {
		evt.preventDefault();
		t.selectionStart = t.selectionEnd = ss + 4;
	}
}

/* Form Logic */

window.addEventListener("load", function (event) {
	var textareas = document.getElementsByTagName("textarea");
	for (var x = 0, xl = textareas.length; x < xl; ++x) {
		textareas[x].addEventListener("keypress", checkTab);
	}

	var form = document.forms["jsv"];
	form.addEventListener("submit", function (event) {
		try {
			var environmentId = form.elements["environment"].value;
			var json =  form.elements["json"].value;
			var jsonUri =  form.elements["json_uri"].value;
			var schema =  form.elements["schema"].value;
			var schemaUri =  form.elements["schema_uri"].value;
			
			try {
				json = json ? JSON.parse(json) : undefined;
			} catch (e) {
				throw new Error("Input is not valid JSON");
			}
			
			try {
				schema = schema ? JSON.parse(schema) : undefined;
			} catch (e) {
				throw new Error("Schema is not valid JSON");
			}
			
			var environment = JSV.createEnvironment(environmentId);
			var report = environment.validate(environment.createInstance(json, jsonUri), environment.createSchema(schema, null, schemaUri));
			var reportElement = document.getElementById("report");
			var output;
			
			if (report.errors.length) {
				reportElement.className = "invalid";
				output = "";
				for (var x = 0, xl = report.errors.length; x < xl; ++x) {
					output += '<div class="error"><span class="error_uri">Problem with <code>' +
						report.errors[x].uri +
						'</code> : </span><span class="error_message">' +
						report.errors[x].message +
						'</span><br/><span class="error_schemaUri">Reported by <code>' +
						report.errors[x].schemaUri +
						'</code></span><br/><span class="error_attribute">Attribute "<code>' +
						report.errors[x].attribute + 
						'</code>"</span><span class="error_details"> (<code>' +
						JSON.stringify(report.errors[x].details) +
						'</code>)</span></div>';
				}
				reportElement.innerHTML = output;
			} else {
				reportElement.className = "valid";
				reportElement.textContent = "Input is valid!";
			}
		} catch (e) {
			var reportElement = document.getElementById("report");
			reportElement.className = "invalid";
			reportElement.textContent = e;
		}
		
		event.preventDefault();
		return false;
	});
});

	</script>
    <script type="text/javascript" src="../lib/uri/uri.js"></script>
    <script type="text/javascript" src="../lib/uri/schemes/urn.js"></script>
    <script type="text/javascript" src="../lib/jsv.js"></script>
    <script type="text/javascript" src="../lib/json-schema-draft-03.js"></script>
    <script type="text/javascript" src="../lib/json-schema-draft-02.js"></script>
    <script type="text/javascript" src="../lib/json-schema-draft-01.js"></script>
</body>
</html>